# Thread splitting bot
# by Cee Pee

from getpass import getpass
import pickle
import os
import re

import forumapi
from deps.Form import Form

def read_data(name="posts"):
	try:
		with open(forumapi.data_file(name, "split"), mode="rb") as f:
			return(pickle.load(f))
	except:
		return(None)

def save_data(data, name="posts"):
	with open(forumapi.data_file(name, "split"), mode="wb") as f:
		pickle.dump(data, f)

def has_powers(me):
	if me.user and me.user._powers:
		return("mod" in me.user.powers or "admin" in me.user.powers)
	else:
		# DWIM (we checked options.mod beforehand)
		return(True)

def settings(settings):
	# TODO: Allow threads/posts/search/tag
	settings.add_option("--post", type="int", help="boundary split: post ID to split from", metavar="ID")
	settings.add_option("--title", help="in case of boundary split, title of the new thread", metavar="TEXT")
	settings.add_option("--forum", type="int", help="forum ID to move split threads to (defaults to thread's forum)", metavar="ID")
	settings.add_option("--file", help="data file to save to or read from")
	settings.add_option("--save", action="store_true", default=False, help="always save data in file")
	settings.add_option("--mod", action="store_true", default=False, help="actually split the thread")
	settings.add_option("--auto", action="store_true", default=False, help="split threads automatically")
	settings.add_option("--merge", action="store_true", default=False, help="Merge posts into threads with an equivalent title")
	
	settings.add_arg("thread", type="int", help="thread ID to work on")

def main(me, options, args):
	auto = options.auto
	
	thread = forumapi.Thread(me, id=args.thread)
	print(repr(thread))
	
	if options.post:
		print("Boundary split: Splitting from post ID {0}.".format(options.post))
		first_post = forumapi.Post(me, id=options.post)
	else:
		first_post = None
	
	if options.file:
		file = options.file
	else:
		file = thread.id
	
	soup = None
	
	data = read_data(file)
	
	if data is not None:
		from_file = True
	else:
		from_file = False
		data = {}
		
		print("Analyzing...")
		thread.retrieve(pages="all")
		
		for post in thread.posts:
			if first_post and post.id < first_post.id:
				continue
			
			subject = post.title
			if subject.startswith("Re: "):
				subject = subject[4:]
			
			if subject not in data:
				data[subject] = []
			
			data[subject].append(post.id)
		
		print("Done reading thread.")
		
		if not options.mod or not has_powers(me) or options.save:
			print("Saving data to '{0}' for later usage.".format(file))
			save_data(data, name=file)
	
	if options.mod:
		if not(from_file or has_powers(me)):
			save_data(data, name=file)
			raise(forumapi.PermissionError("Cannot perform moderation."))
		
		print("Splitting threads {0}automatically.".format("" if auto else "semi-"))
		
		if options.forum:
			forum = forumapi.Forum(me, id=options.forum)
		else:
			forum = thread.forum
		
		for title, posts in data.copy().items():
			print("Using posts with subject '{0}'".format(title))
			ids = ",".join([str(int(post)) for post in posts])
			print("IDs: {0}".format(ids))
			
			if title == thread.title and not options.post:
				print("Not spliting because the posts have the same title as the thread.")
				continue
			
			cont = None
			
			if options.merge:
				# Quoted search for title
				threads = me.get_search_results('"{0}"'.format(title), titleonly=True)
				count = len(threads)
				if count == 0:
					print("Did not find any threads to merge into{0}.".format("" if auto else ", use M to manually select or Y to split"))
				elif count == 1 and threads[0].title == title:
					merge = threads[0].id
					print("Found a thread with id {0} and same subject to merge into{1}.".format(merge, "" if auto else ", use Y to continue"))
				else:
					print("Found {0} threads to merge into{1}".format(count, "." if auto else ", use M to choose one or Y to split the posts:"))
					if not auto:
						for thread in threads:
							print(repr(thread))
			else:
				merge = False
			
			if options.post and options.title:
				new_title = options.title
			else:
				new_title = title
			
			if auto:
				cont = "Y"
			else:
				cont = input("Continue? ([Y]es/[N]o/[M]erge/[F]orum/[T]itle/[A]uto/[Q]uit) ").upper()
			
			if cont == "A":
				auto = True
			elif cont == "M":
				merge = int(input("Thread ID to merge into (0 to cancel): "))
			elif cont == "F":
				forumid = int(input("Forum ID to put new threads in (0 to cancel, current: {0}): ".format(forum.id)))
				if forumid != 0:
					forum = forumapi.Forum(me, id=forumid)
			elif cont == "T":
				new_title = input("Thread title to use (current: '{0}'): ".format(newtitle))
			elif cont == "N":
				print("Not splitting these posts.")
				continue
			elif cont == "Q":
				quit_file = "{0}-q".format(file)
				print("Saving remaining data to '{0}'...".format(quit_file))
				save_data(data, name=quit_file)
				return(None)
			
			if soup:
				soup_form = soup.find("form", action=lambda url: "inlinemod" in url)
				post_data = Form(soup_form, session=me).get_post_data()
			else:
				post_data = {
					"s": "",
					"securitytoken": me.get_security_token(),
				}
			
			post_data["postids"] = ids
			post_data["t"] = thread.id
			post_data["do"] = "domoveposts"
			
			if merge:
				post_data["type"] = "1"
				post_data["mergethreadurl"] = "{0}/showthread.php?t={1}".format(me.site.url, merge)
			else:
				post_data["type"] = "0"
				post_data["destforumid"] = forum.id
				post_data["title"] = new_title
			
			mod_page = me.get_page("inlinemod.php?do=domoveposts&t={0}".format(thread.id), post_data=post_data)
			
			mod_soup = me.soup(mod_page)
			mod_form = mod_soup.find("form", action=lambda url: "do=login" in url)
			if mod_form:
				print("Verifying legitimacy of the request...")
				mod_form = Form(mod_form, session=me)
				
				password_file = forumapi.data_file(options.password, "pw")
				
				if os.access(password_file, os.R_OK):
					password = open(password_file).read()
				elif options.auth == "input":
					password = options.password
				else:
					password = getpass()
				
				mod_form["vb_login_password"] = password
				
				mod_form.submit()
				
				# Try again after receiving cookies
				print("Probably logged in, retrying.")
				me.get_page("inlinemod.php?do=domoveposts&t={0}".format(thread.id), post_data=post_data)
			
			# Remove data so that quitting does not write handled data
			del(data[title])
	
	print("Done.")

if __name__ == "__main__":
	forumapi.run(main, options=settings, supported_types=["vbulletin"])
